using System;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Diagnostics;

namespace System.IO.IsolatedStorage
{
    public class PSDirectoryInfo : AbstractDirectoryInfo //:FileSystemInfo
    {
        string originalPath;
        string cleanedPath;

        public PSDirectoryInfo(string path)
        {
            if (!path.EndsWith(@"\"))
                path += @"\";
            originalPath = PSDirectory.FixRelativePath(path);

            cleanedPath = (path.StartsWith(@"\") ? path.Substring(1) : path);
        }

        private string removeTrailingSlash()
        {
            return originalPath.EndsWith(@"\") ? originalPath.Substring(0, originalPath.Length - 1) : originalPath;
        }

        private string[] pathExtractor()
        {
            var temp = removeTrailingSlash();
            var temp2 = temp.Split('\\');
            return temp2;
        }

        public override bool Exists { get { return PSDirectory.Exists(originalPath); } }

        public override string Name
        {
            get
            {
                string[] temp2 = pathExtractor();
                if (temp2.Length > 0)
                    return temp2[temp2.Length - 1];
                return "";
            }
        }

        public override string FullName
        {
            get
            {
                return originalPath;
            }
        }

        public override AbstractDirectoryInfo Parent
        {
            get
            {
                var temp = removeTrailingSlash();
                if (temp.Length < 1)
                    return Root;
                var lastSlash = temp.LastIndexOf(temp.Substring(1));
                if (lastSlash == -1)
                    return Root;
                return new PSDirectoryInfo(temp.Substring(0, lastSlash));
            }
        }

        public override AbstractDirectoryInfo Root { get { return new PSDirectoryInfo(@"\"); } }

        public override void Create()
        {
            PSDirectory.CreateDirectory(originalPath);
        }

        public override AbstractDirectoryInfo CreateSubdirectory(string path)
        {
            var slash = "";
            if (!((originalPath.Length > 0 && originalPath.EndsWith(@"\")) ||
                (path.StartsWith(@"\"))))
            {
                slash = @"\";
            }
            var newPath = originalPath + slash + path;
            var result = new PSDirectoryInfo(newPath);
            result.Create();
            return result;
        }

        public override void Delete()
        {
            PSDirectory.Delete(originalPath);
        }

        public override void Delete(bool recursive)
        {
            PSDirectory.Delete(originalPath, recursive);
        }

        private string EnsurePathEndsInASlash()
        {
            var result = originalPath + (originalPath.EndsWith(@"\") ? "" : @"\");
            return result.Replace(@"\\", @"\");
        }

        public override AbstractDirectoryInfo[] GetDirectories()
        {
            if (this.cleanedPath == @"\\")
            {
                Debug.WriteLine("this is the root! fixing directories get");
                Debug.WriteLine("PSDirectory.GetDirectories(@\"\\*\") returns a count of: " + PSDirectory.GetDirectories(@"\*").Count());

                return DirNamesArrayToISDirInfo(PSDirectory.GetDirectories(@"\*"));
            }
            Debug.WriteLine("EnsurePathEndsInASlash() returns: " + EnsurePathEndsInASlash());
            Debug.WriteLine("PSDirectory.GetDirectories(EnsurePathEndsInASlash()) returns a count of: " + PSDirectory.GetDirectories(EnsurePathEndsInASlash()).Count());
            return DirNamesArrayToISDirInfo(PSDirectory.GetDirectories(EnsurePathEndsInASlash()));
        }

        public override AbstractDirectoryInfo[] GetDirectories(string searchPattern)
        {
            Debug.WriteLine("EnsurePathEndsInASlash() returns: " + EnsurePathEndsInASlash());
            Debug.WriteLine("searchPattern: " + searchPattern);
            Debug.WriteLine("PSDirectory.GetDirectories(EnsurePathEndsInASlash(), searchPattern) returns a count of: " + PSDirectory.GetDirectories(EnsurePathEndsInASlash(), searchPattern).Count());

            return DirNamesArrayToISDirInfo(PSDirectory.GetDirectories(EnsurePathEndsInASlash(), searchPattern));
        }

        private AbstractDirectoryInfo[] DirNamesArrayToISDirInfo(string[] dirs)
        {
            return (from item in dirs
                    select new PSDirectoryInfo(item)).ToArray();
        }

        public override AbstractFileInfo[] GetFiles()
        {
            return (from item in PSDirectory.GetFiles(EnsurePathEndsInASlash())
                    select new PSFileInfo(item)).ToArray();
        }

        public override AbstractFileInfo[] GetFiles(string searchPattern)
        {
            return (from item in PSDirectory.GetFiles(EnsurePathEndsInASlash(), searchPattern)
                    select new PSFileInfo(item)).ToArray();
        }

        public AbstractFileSystemInfo[] GetFileSystemInfos()
        {
            var dirs = GetDirectories().Select(item => (AbstractFileSystemInfo)item).AsEnumerable();
            var files = GetFiles().Select(item => (AbstractFileSystemInfo)item).AsEnumerable();
            var result = new List<AbstractFileSystemInfo>();
            result.AddRange(dirs);
            result.AddRange(files);
            return result.ToArray();
        }

        public AbstractFileSystemInfo[] GetFileSystemInfos(string searchPattern)
        {
            var dirs = GetDirectories(searchPattern).Select(item => (AbstractFileSystemInfo)item).AsEnumerable(); ;
            var files = GetFiles(searchPattern).Select(item => (AbstractFileSystemInfo)item).AsEnumerable(); ;
            var result = new List<AbstractFileSystemInfo>();
            result.AddRange(dirs);
            result.AddRange(files);
            return result.ToArray();
        }

        public override void MoveTo(string destDirName)
        {
            PSDirectory.Move(originalPath, destDirName);
            this.originalPath = PSDirectory.FixPath(destDirName);
        }

        public override string ToString()
        {
            return originalPath;
        }

        public override bool SupportsAsync
        {
            get { return true; }
        }

        public override bool SupportSync
        {
            get { return true; }
        }

        public override void MoveToAsync(AbstractDirectoryInfo dir, Action<Exception> callback)
        {
            throw new NotImplementedException();
        }

        public override void MoveToAsync(string destDirName, Action<Exception> callback)
        {
            try
            {
                MoveTo(destDirName);
                callback(null);
            }
            catch (Exception ex)
            {
                callback(ex);
            }
        }

        public override void GetFilesAsync(string searchPath, Action<AbstractFileInfo[], Exception> callback)
        {
            try
            {
                var results = GetFiles(searchPath);
                callback(results, null);
            }
            catch (Exception ex)
            {
                callback(null, ex);
            }
        }

        public override void GetFilesAsync(Action<AbstractFileInfo[], Exception> callback)
        {
            try
            {
                var results = GetFiles();
                callback(results, null);
            }
            catch (Exception ex)
            {
                callback(null, ex);
            }
        }

        public override void DeleteAsync(bool recursive, Action<Exception> callback)
        {
            try
            {
                Delete(recursive);
                callback(null);
            }
            catch (Exception ex)
            {
                callback(ex);
            }
        }

        public override void CreateSubdirectoryAsync(string path, Action<AbstractDirectoryInfo, Exception> callback)
        {
            try
            {
                var result = CreateSubdirectory(path);
                callback(result, null);
            }
            catch (Exception ex)
            {
                callback(null, ex);
            }
        }

        public override void CreateAsync(Action<Exception> callback)
        {
            try
            {
                Create();
                callback(null);
            }
            catch (Exception ex)
            {
                callback(ex);
            }
        }

        public void MoveTo(AbstractFileInfo file)
        {
            throw new NotImplementedException();
        }

        public override void DeleteAsync(Action<Exception> errorCallback)
        {
            Exception ex = null;
            try
            {
                Delete();
            }
            catch (Exception e)
            {
                ex = e;
            }
            errorCallback(ex);
        }

        public override void GetExistsAsync(Action<bool> callback)
        {
            callback(Exists);
        }

        public override void LoadInfo(Action<bool> callback)
        {
            callback(true); // totally synchronous process
        }
    }
}